import qs from 'qs';
const isPlainObject = function isPlainObject(obj) {
  let proto, Ctor;
  if (!obj || Object.prototype.toString.call(obj) !== '[object Object]')
    return false;
  proto = Object.getPrototypeOf(obj);
  if (!proto) return true;
  Ctor = proto.hasOwnProperty('constructor') && proto.constructor;
  return typeof Ctor === 'function' && Ctor === Object;
};

let baseURL = 'http://127.0.0.1:9999',
  inital = {
    method: 'GET',
    params: null,
    body: null,
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
  };

export default function request(url, config) {
  if (typeof url !== 'string') throw new TypeError('url must be required!');
  if (!isPlainObject(config)) config = {};
  if (config.headers) {
    if (!isPlainObject(config.headers)) config.headers = {};
    config.headers = Object.assign({}, inital.headers, config.headers);
  }
  let { method, params, body, headers } = Object.assign({}, inital, config);

  // 处理URL
  if (!/^http(s?):\/\//i.test(url)) url = baseURL + url;
  if (params != null) {
    if (isPlainObject(params)) params = qs.stringify(params);
    url += `${url.includes('?') ? '&' : '?'}${params}`;
  }

  // 处理请求主体
  let isPost = /^(POST|PUT|PATCH)$/i.test(method);
  if (isPost && body != null && isPlainObject(body)) {
    body = qs.stringify(body);
  }

  // 发送请求
  config = {
    method: method.toUpperCase(),
    headers,
  };
  if (isPost) config.body = body;
  return fetch(url, config)
    .then((response) => {
      // 只要服务器有返回值，则都认为promise是成功的，不论状态码是啥
      let { status, statusText } = response;
      if (status >= 200 && status < 300) {
        // response.json():把服务器获取的结果变为json格式对象，返回的一个promise实例
        return response.json();
      }
      return Promise.reject({
        code: 'STATUS ERROR',
        status,
        statusText,
      });
    })
    .catch((reason) => {
      // @1 状态码错误
      if (reason && reason.code === 'STATUS ERROR') {
        // ...
      }

      // @2 断网
      if (!navigator.onLine) {
        // ...
      }

      return Promise.reject(reason);
    });
}
